package com.fc.incross_server.engine;

import com.fc.incross_server.filter.ServerRequestFilter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.*;

/**
 * @Author: GY.
 * @Description: 启动服务端
 * @Date:Created in 2020/2/24 0024.
 * @Modified By:
 */
@Component
public class Server implements InitializingBean {
    //    @Value("#{incross.server.port}")
    public final static int serverPort = 10001;
    private static ExecutorService executorService = Executors.newSingleThreadExecutor();

    public static volatile Map<String, byte[]> responseByteMap = new HashMap<>(1024);
    // 支持1个客户端长连接
    private static ThreadPoolExecutor serverThreadPool = new ThreadPoolExecutor(
            1, 1, 0, TimeUnit.SECONDS,
            new SynchronousQueue<>(),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    private static class StartServerTask implements Runnable {
        @Override
        public void run() {
            System.out.println("================serverPort================" + serverPort);
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket(serverPort);
            } catch (IOException e) {
                e.printStackTrace();
            }
            while (true) {
                Socket socket = null;
                try {
                    socket = serverSocket.accept();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                new ClientLinkTask(socket).execute();
            }
        }
        public void execute() {
            executorService.execute(this);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("================Server================");
        new StartServerTask().execute();
    }

    private static class ClientLinkTask implements Runnable {
        private Socket socket;

        ClientLinkTask(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                InputStream inputStream = socket.getInputStream();
                byte[] b = new byte[1024];
                inputStream.read(b);
                System.out.println("CLIENT LINKED===========" + new String(b, "utf-8") + "================");
                while (true) {
                    if (ServerRequestFilter.requestByteMap.size() == 0) {
                        synchronized ("requestByteMap") {
                            try {
                                "requestByteMap".wait();
                                continue;
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    Set<Map.Entry<String, byte[]>> entries = ServerRequestFilter.requestByteMap.entrySet();
                    for (Map.Entry<String, byte[]> entry : entries) {
                        String key = entry.getKey();
                        byte[] bytes = entry.getValue();
                        OutputStream outputStream = socket.getOutputStream();
                        outputStream.write(bytes);
                        outputStream.flush();
                        b = new byte[4096];
                        inputStream.read(b);
                        responseByteMap.put(key,b);
                        ServerRequestFilter.requestByteMap.remove(key);
                        synchronized (key) {
                            key.notifyAll();
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void execute() {
            serverThreadPool.execute(this);
        }
    }
}
